#ifndef BGV_NUMB_H_
#define BGV_NUMB_H_
#include "common.h"
#include <arm_neon.h>
#include <ctime>
#include <iostream>
#include <set>
#include <vector>
using namespace std;
/* *
 * @file numb.h
 * @brief 模运算和Barrett约简算法的头文件。
 *
 * 本文件声明了执行各种模运算操作的函数，包括使用Barrett和Shoup方法的优化实现。
 * 还包含用于数论操作的实用函数，如寻找素因数、原根以及进行素数测试。
 */

void Negate(uint64_t &r, uint64_t a);
void AddMod(uint64_t &r, uint64_t a, uint64_t b, uint64_t p);
uint64_t SingleBarrettNew(__uint128_t &a, uint64_t q, uint64_t muHigh, uint64_t muLow);
uint64_t Barrett128(__uint128_t &a, uint64_t q, uint64_t mu_high, uint64_t mu_low);
uint64_t Barrett64(uint64_t a, uint64_t q, uint64_t mu);
void Barrett64NEON(uint64x2_t *res, uint64x2_t a, uint64x2_t q, uint64x2_t mu);
void AddModAndEqual(uint64_t &a, uint64_t b, uint64_t p);
void SubMod(uint64_t &r, uint64_t a, uint64_t b, uint64_t m);
void SubModAndEqual(uint64_t &a, uint64_t b, uint64_t q);
void MulMod(uint64_t &r, uint64_t a, uint64_t b, uint64_t m);
void MulModBarrett(uint64_t &r, uint64_t a, uint64_t b, uint64_t p, uint64_t twop, uint64_t prHigh, uint64_t prLow);
void ModBarrett(uint64_t &r, uint64_t a, uint64_t p, uint64_t twop, uint64_t prHigh, uint64_t prLow);
void ModBarrett(uint64_t &r, unsigned __int128 a, uint64_t p, uint64_t twop, uint64_t prHigh, uint64_t prLow);
uint64_t InvMod(uint64_t x, uint64_t m);
uint64_t PowMod(uint64_t x, uint64_t y, uint64_t modulus);
uint64_t Inv(uint64_t x);
uint64_t Pow(uint64_t x, uint64_t y);
uint32_t BitReverse(uint32_t x);
uint64_t Gcd(uint64_t a, uint64_t b);
long Gcd(long a, long b);
void FindPrimeFactors(std::set<uint64_t> &s, uint64_t number);
uint64_t FindPrimitiveRoot(uint64_t modulus);
uint64_t FindMthRootOfUnity(uint64_t M, uint64_t mod);
bool PrimeTest(uint64_t p);
uint64_t x_Shoup(uint64_t x, uint64_t p);
void MulModShoup(uint64_t &res, uint64_t a, uint64_t b, uint64_t bShoup, uint64_t q);
void MulModBarrett_NEON(uint64x2_t *r, uint64x2_t a, uint64x2_t b, uint64x2_t p, uint64x2_t twop, uint64x2_t prHigh,
    uint64x2_t prLow);
void AddMod_NEON(uint64x2_t *r, uint64x2_t a, uint64x2_t b, uint64x2_t p);
void MulModShoup_NEON(uint64x2_t *result, uint64x2_t a, uint64x2_t b, uint64x2_t bShoup, uint64x2_t q);
int BitsLen64(uint64_t x);
int DecompRNS(int levelQ, int levelP);
int OverflowMargin(int level, uint64_t *vec);
int DecompPw2(int levelQ, int levelP, int pow2Base, vector<uint64_t>& qVec, vector<uint64_t>& pVec);
int MaxBit(int levelQ, int levelP, vector<uint64_t>& qVec, vector<uint64_t>& pVec);
void ComSubQ(uint64_t &a, uint64_t q);
void ComSubQNeon(uint64x2_t &a, uint64x2_t q);
#endif